package property.maven.plugin;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.Reader;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Execute;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import property.maven.plugin.check.name.BuiltInCheckNameEnum;
import property.maven.plugin.check.validator.BlankValuesValidator;
import property.maven.plugin.check.validator.CustomValidator;
import property.maven.plugin.check.validator.EmptySpaceEndValidator;
import property.maven.plugin.io.xpp3.PropertiesCheckerNameXpp3Reader;


/**
 * <br/>
 * 
 * This goal apply validation checks at the provided java.util.Properties files.<br/>
 * 
 * The available checks names are: <br/>
 * <ol>
 * <li>
 * EMPTY_SPACES_END <br/> <br/>
 *  
 * Check for blanks spaces at the end of value entry
 *  
 *  <pre>
 *  {@code
 *  <check>
 *		<checkName>EMPTY_SPACES_END</checkName>
 *	</check>
 *  
 *  }
 *  </pre>
 *   
 *  <br/>
 *  
 * </li>
 * <li>
 * BLANK_VALUES <br/> <br/>
 *  
 * Check for key without value
 *  
 *  <pre>
 *  {@code
 *  <check>
 *		<checkName>BLANK_VALUES</checkName>
 *	</check>
 *  }
 *  </pre>
 *   
 *  <br/>
 *  
 * </li>
 * 
 * <li>
 * CUSTOM_REGEXP <br/> <br/>
 *  
 * Apply a custom validation regular expression at each key: if it matches the build fail. <br/>
 * Use <![CDATA[ your regexp ]]>  if necessary. <br/>
 *  
 *  <pre>
 *  {@code
 *  <check>
 *		<checkName>CUSTOM_REGEXP</checkName>
 *      <checkValue>regexp to use</checkValue>
 *	</check>
 *  }
 *  </pre>
 *   
 *  <br/>
 *  
 * </li>
 * 
 * </ol>
 *  
 * <br/><br/>
 * 
 * To execute the plugin: <br/>
 *  <code>mvn -e property.maven.plugin:maven-property-checker:1.0-SNAPSHOT:check;</code>
 * 
 * @author fulvio 
 * 
 */
@Mojo( name = "check" )
@Execute( goal = "verify", phase = LifecyclePhase.COMPILE)
public class PropertiesCheckerMojo extends AbstractMojo
{	
	/**
	 * An xml input file with files to checks and validator(s) to use on them
	 */
	@Parameter
	private File verificationFile;
	
	/**
     * The Project base directory (it is a Maven system property).
     */
	@Parameter (property = "basedir")
    private File projectBasedir;
	
	/**
	 * {@inheritDoc}
	 */
    public void execute() throws MojoExecutionException
    {
    	getLog().info("**************** Properties validation **********************");       
        
        Reader inputXmlReader = null;
       
        try{        	
        	inputXmlReader = new FileReader(this.verificationFile);

            //use the reader and pojo objects generated by Modello 
            PropertiesCheckerNameXpp3Reader xppReader = new PropertiesCheckerNameXpp3Reader();
            PropertyChecker propertyChecker = xppReader.read(inputXmlReader);           
            
            for(Iterator i = propertyChecker.getCheckBlock().iterator(); i.hasNext(); )
            {
        	   property.maven.plugin.CheckBlock propertiesFileToCheck = (CheckBlock) i.next();
        	  
        	   String relativeFilePath = propertiesFileToCheck.getFileLocation();
        	   
               if (relativeFilePath != null)
               {   
            	  // full path of the properties file to check 
            	  String absoluteFilePath = getAbsolutePathFileToCheck(new File(relativeFilePath)).getPath();
            	   
            	  propertiesFileToCheck.setFileLocation(absoluteFilePath);
                  getLog().info("- Checking: "+absoluteFilePath);
        	   
                  /**
                   * Note: loading the provided properties file in a java.util.Properties we reuse the java parser 
                   */
                  Properties propertiesFile = loadFileProperties(absoluteFilePath);                  
           
        	      // checks list to apply at the current file
        	      List<Check> checkList = propertiesFileToCheck.getChecks();
        	      String chekName;
        	      
        	      // apply check(s) at each properties file entry
        	      for(Iterator j = checkList.iterator(); j.hasNext();) {
        		   
        	    	  property.maven.plugin.Check check = (property.maven.plugin.Check) j.next();     
        	    	  chekName = check.getCheckName();
        	    	  
        	    	  getLog().info("Applying check: "+chekName);
        	    	  
        	    	  if(chekName.equalsIgnoreCase(BuiltInCheckNameEnum.EMPTY_SPACES_END.name())){
        	    		  
        	    		  EmptySpaceEndValidator emptySpaceEndValidator = new EmptySpaceEndValidator();
        	    		  emptySpaceEndValidator.validate(propertiesFile,relativeFilePath);
        	    		  
        	    	  } else if(chekName.equalsIgnoreCase(BuiltInCheckNameEnum.BLANK_VALUES.name())){
        	    		  
        	    		  BlankValuesValidator blankValuesValidator = new BlankValuesValidator();
        	    		  blankValuesValidator.validate(propertiesFile,relativeFilePath);
        	    		  
        	    	  }else if(chekName.equalsIgnoreCase(BuiltInCheckNameEnum.CUSTOM_REGEXP.name())){

        	    		  // the user defined regexp to use
              	    	  String chekValue = check.getCheckValue();
        	    		  CustomValidator customValidator = new CustomValidator();
        	    		  customValidator.validate(propertiesFile,relativeFilePath,chekValue);
        	    		  
        	    	  } else {
        	    		  //unsupported validator name
        	    		  throw new MojoExecutionException("Invalid validator name, use 'help' goal for usage" );
        	    	  }
          	      }        	 
                
               }
               else
               {
            	   //stop the build process
                   throw new MojoExecutionException("Missing required <fileLocation> element, use 'help' goal for usege" );
               }   
         }       
           
        }catch (Exception e) {        	
        	throw new MojoExecutionException( "Error during the execution:"+e.getMessage());
		}
        
        getLog().info("**************************************");  
   }

    
    /**
     * Utility method that transform the properties file to check into an absolute path prefixing the basedir if the location is relative
     * (For the file accessing, location... Maven plugin use some utility provided by Plexus)	
     * @param file the file path of the file to check (can be relative or absolute). If relative
     *             the project's basedir will be prefixed.
     * @return the absolute file path of the file to check
     */
    private File getAbsolutePathFileToCheck( File file )
    {
        File result = file;
        if ( !file.isAbsolute() )
        {
          result = new File( projectBasedir , file.getPath() );
        }
        return result;
    }
    
    /**
     * Load in a java.util.Properties object the content of the provided input file
     * 
     * @param filePath The full path name at the properties file to check
     * @return A java properties object with properties contained in the provide file
     * @throws Exception if errors loading the file
     * 
     */
    private Properties loadFileProperties(String filePath) throws Exception{
    	
    	Properties prop = new Properties();
 	    prop.load(new FileInputStream(new File(filePath)));
 	    
 	    return prop;
    }
    
    
	public void setVerificationFile(File verificationFile) {
		this.verificationFile = verificationFile;
	}


	public void setProjectBasedir(File projectBasedir) {
		this.projectBasedir = projectBasedir;
	}


}
